home *** CD-ROM | disk | FTP | other *** search
- /*
- File: GDeviceWindow.cp
-
- Contains: A window that displays information about a GDevice
-
- Written by: Kent Miller
-
- Copyright: © 1995 Apple Computer
-
- Change History (most recent first):
-
- */
-
- #include <Displays.h>
-
- //Isn't it nice to double the size of your app so you
- //can do sprintf?
- #include <stdio.h>
- #include <string.h>
-
- //Sprocket includes
- #include "MenuBar.h"
-
- //SuperFly includes
- #include "GDeviceWindow.h"
- #include "GDeviceUtilities.h"
- #include "SuperFly.h"
-
-
- const short kGDeviceWindowTemplateID = 1026;
-
-
- TGDeviceWindow::TGDeviceWindow()
- {
- this->theID = kInvalidDisplayID;
- }
-
- TGDeviceWindow::~TGDeviceWindow()
- {
- }
-
- WindowPtr
- TGDeviceWindow::MakeNewWindow(WindowPtr behindWindow)
- {
- WindowPtr aWindow = GetNewWindow(kGDeviceWindowTemplateID,nil,behindWindow);
- char titleString[256];
- GDHandle thisWindowsGD, mirroredGD;
- Rect gdRect, windowRect;
- DisplayIDType mirroredID;
- SInt16 hMove, vMove;
- OSErr err = noErr;
-
- if (aWindow)
- {
- //make the window exciting & different, center this window on it's GDevice
- DMGetGDeviceByDisplayID(this->theID, &thisWindowsGD, false);
-
- // if this fails, we're in big trouble
- if (thisWindowsGD == nil)
- {
- CloseWindow(aWindow);
- return nil;
- }
-
- gdRect = (**thisWindowsGD).gdRect;
- OffsetRect(&gdRect, -gdRect.left, -gdRect.top); //move it to 0,0
-
- windowRect = aWindow->portRect;
- OffsetRect (&windowRect, -windowRect.left, -windowRect.top);
-
- CenterRectInRect(&gdRect, &windowRect, &hMove, &vMove);
-
- hMove = (**thisWindowsGD).gdRect.left + hMove;
- vMove = (**thisWindowsGD).gdRect.top + vMove;
-
- MoveWindow(aWindow, hMove, vMove, false);
-
- //Create the title for the window out of Display's ID
- sprintf(titleString, "Display ID = %ld", this->theID);
-
- //Add the display IDs of all mirrored displays to the window title.
- //Hopefully, the title won't grow too much.
-
- mirroredGD = thisWindowsGD;
- while (err == noErr)
- {
- err = DMGetNextMirroredDevice(mirroredGD, &mirroredGD);
- if (mirroredGD == thisWindowsGD)
- break; //we've come around in a loop
- if (err == noErr)
- {
- err = DMGetDisplayIDByGDevice(mirroredGD, &mirroredID, false);
- if ((strlen(titleString)< 230)) //Watch out for big window titles!
- sprintf(titleString, "%s, %ld", titleString, mirroredID);
- }
-
- }
-
- c2pstr(titleString);
-
- SetWTitle(aWindow,(unsigned char *)titleString);
- ShowWindow(aWindow);
- }
-
- return aWindow;
- }
-
- void
- TGDeviceWindow::Click(EventRecord * /* anEvent */)
- {
- this->Select();
- }
-
- void
- TGDeviceWindow::Activate(Boolean activating)
- {
- if (activating)
- this->Select();
- }
-
- OSErr
- TGDeviceWindow::SetUpData(GDHandle theGD)
- {
- OSErr err;
-
- err = DMGetDisplayIDByGDevice(theGD, &this->theID, false);
-
- this->CreateWindow();
-
- return (err);
- }
-
- void
- TGDeviceWindow::Draw(void)
- {
- unsigned char s[256];
- DeviceLoopDrawingUPP myDrawingProcUPP;
- GrafPtr savePort;
- RgnHandle myWindowsRgn;
- SInt16 familyID;
- Point p = { 20, 20}; //Draw Text Here
- GDHandle theGD;
-
- GetPort(&savePort);
- SetPort(this->fWindow);
-
- GetFNum("\pHelvetica",&familyID);
- TextFont(familyID);
- TextSize(18);
- ForeColor(blackColor);
-
- ClipRect(&(this->fWindow->portRect));
-
- //Make a region that is my Window's StrucRgn only in local coordinates.
- myWindowsRgn = NewRgn();
- if (!myWindowsRgn)
- return;
- CopyRgn(( (WindowPeek)this->fWindow)->strucRgn, myWindowsRgn);
- OffsetRgn(myWindowsRgn, -(**myWindowsRgn).rgnBBox.left, -(**myWindowsRgn).rgnBBox.top);;
-
-
- //For this app, we will draw the parts of the window that are common to them
- //using quickdraw commands and the parts that are different using device loop.
- //
- //First, use Device Loop to draw. When there is a mirrored device, the
- //drawing proc will be called twice and we can draw different things each time.
- //We could draw the same thing each time, but that would be boring.
- myDrawingProcUPP = NewDeviceLoopDrawingProc (GDeviceWindowDrawingProc);
- DeviceLoop( myWindowsRgn, myDrawingProcUPP, (SInt32) this->fWindow, 0);
- DisposeRoutineDescriptor(myDrawingProcUPP);
- DisposeRgn(myWindowsRgn);
-
- //Then draw the common parts. We are doing things in this order since the device
- //loop proc fills the window's background.
- DMGetGDeviceByDisplayID( this->theID, &theGD, false );
-
- sprintf ((char *)s, "Global rect: (%d,%d) (%d,%d)",
- (**theGD).gdRect.top, (**theGD).gdRect.left,
- (**theGD).gdRect.bottom, (**theGD).gdRect.right);
-
- c2pstr((char *)s);
- MoveTo(p.h,p.v);
- DrawString(s);
-
-
- SetPort(savePort);
- }
-
- void DrawThisCStringHere(unsigned char * s, SInt16 h, SInt16 v)
- //Converts the string to a PString in place
- {
- MoveTo(h, v);
- c2pstr((char *)s);
- DrawString(s);
- }
-
- void SetRampRGBColor(RGBColor * theRGB, SInt16 value, SInt16 rampColor)
- {
- theRGB->red = 0;
- theRGB->green = 0;
- theRGB->blue = 0;
-
- switch (rampColor)
- {
- case 0:
- theRGB->red = value;
- break;
-
- case 1:
- theRGB->green = value;
- break;
-
- case 2:
- theRGB->blue = value;
- break;
-
- case 3: //a Gray ramp
- theRGB->red = value;
- theRGB->green = value;
- theRGB->blue = value;
- break;
- }
- }
-
-
- void DrawARamp(SInt16 depth, Rect * rampRect )
- //Don't ask me to comment this code, I just ripped it off from a "reliable" source.
- //For indexed color modes, use the system color table.
- //For direct color modes, just draw ramps.
- {
- SInt16 i, j, h, v;
- RGBColor rgb, savedFore;
- Rect tempRect;
- SInt32 hsteps;
- SInt16 vsteps,hsides,vsides;
-
- GetForeColor(&savedFore);
-
- if (depth > 8) //direct ramp
- {
- hsteps = rampRect->right - rampRect->left;
- hsides = 1;
- vsides = (rampRect->bottom - rampRect->top) / 4;
- for (i = 0; i< hsteps; i++)
- {
- j = ((i+1) * (0x0000FFFF / hsteps)) - 1;
- MoveTo(rampRect->left + i, rampRect->top);
- SetRampRGBColor(&rgb, j, 0);
- RGBForeColor(&rgb);
- Line(0, vsides);
- SetRampRGBColor(&rgb, j, 1);
- RGBForeColor(&rgb);
- Line(0, vsides);
- SetRampRGBColor(&rgb, j, 2);
- RGBForeColor(&rgb);
- Line(0, vsides);
- SetRampRGBColor(&rgb, j, 3);
- RGBForeColor(&rgb);
- Line(0, vsides-1);
- }
- }
- else //Indexed ramp - this doesn't behave like "Monitors" does in Grayscale mode.
- //If you want Grayscale ramps to behave differently, you could attach a palette
- //to the window and call PMForeColor.
- {
- //window
- Handle clutRsrc;
- PaletteHandle ourPalette;
-
- clutRsrc = RGetResource('clut', depth);
- ourPalette = NewPalette(256, CTabHandle(clutRsrc), pmExplicit, 0);
- ReleaseResource(clutRsrc);
-
- hsteps = Max( 1 << (depth/2+1) , 2);
- vsteps = Max( 1 << (depth/2-1) , 1);
- hsides = (rampRect->right - rampRect->left) / hsteps;
- vsides = (rampRect->bottom - rampRect->top) / vsteps;
-
-
- for (i=0; i < vsteps; i++)
- for (j=0; j < hsteps; j++)
- {
- GetEntryColor(ourPalette, ((1<< depth) - 1) - (i*hsteps+j), &rgb);
- RGBForeColor(&rgb);
-
- h = j * hsides;
- v = i * vsides;
- SetRect(&tempRect, rampRect->left + h, rampRect->top + v,
- rampRect->left + h + hsides, rampRect->top + v + vsides);
- FillRect(&tempRect, &qd.black);
- }
- DisposePalette(ourPalette);
-
- }
-
- RGBForeColor(&savedFore);
- }
-
- void DrawMiniMonitors(Rect *drawHere, GDHandle thisGDevice)
- {
- RgnHandle theGrayRgn = LMGetGrayRgn();
- TLinkedList *myGDList;
- GDHandle theGD;
- Rect r, drawHereTemp;
- RgnHandle saveClip = NewRgn();
- Point origin;
- SInt16 hOffset, vOffset;
- PixPatHandle theDesktopPattern;
-
- //For speed, we should probably cache this list since Display Manager notification
- //tells us every time this changes.
- myGDList = BuildAListOfUniqueDevices();
-
- //start framing the devices
- EraseRect(drawHere);
- FrameRect(drawHere);
-
- GetClip(saveClip);
- ClipRect(drawHere);
-
- //Figure out where the 0,0 point will be in the drawHere rect.
- //Set r to the desktop rgn and scale it
- r = (**theGrayRgn).rgnBBox;
- r.top /= 10;
- r.left /= 10;
- r.bottom/= 10;
- r.right /= 10;
-
- //Where is 0,0 in the scaled rectangle?
- origin.h = ( - r.left ); //r.left will either be zero or some negative number
- origin.v = ( - r.top ); //ditto for the top
-
- OffsetRect( &r, -r.left, -r.top );
-
- //Center it in theDrawHere rect
- //This might not work if r's bounds are bigger than the drawHere bounds, who knows?
- drawHereTemp = *drawHere;
- OffsetRect( &drawHereTemp, -drawHereTemp.left, -drawHereTemp.top );
- CenterRectInRect(&drawHereTemp, &r, &hOffset, &vOffset);
- OffsetRect( &r, hOffset, vOffset);
-
- //Now, just find where the origin is in the scaled rectangle
- origin.h += r.left + drawHere->left;
- origin.v += r.top + drawHere->top;
-
-
- theGD = (GDHandle) myGDList->GetFirstListElem();
- while (theGD)
- {
- r = (**theGD).gdRect;
-
- r.top /= 10;
- r.left /= 10;
- r.bottom/= 10;
- r.right /= 10;
-
- OffsetRect(&r, origin.h, origin.v);
-
- FrameRect(&r);
-
- //If this is my rect, then fill it with the desktop rect
- //If it isn't, fill it with Gray
- InsetRect(&r, 1, 1);
- if ( EqualRect (&(**theGD).gdRect, &(**thisGDevice).gdRect))
- {
- //Get the current desktop pattern from the system file.
- theDesktopPattern = GetPixPat(16);
- if (theDesktopPattern)
- {
- FillCRect(&r, theDesktopPattern);
- DisposePixPat(theDesktopPattern);
- }
- }
- else
- FillRect(&r, &qd.gray);
-
- //If this is the main display, draw a wonky little menu bar
- if (TestDeviceAttribute (theGD, mainScreen))
- {
- r.bottom = r.top + 5;
- EraseRect(&r);
- MoveTo( r.left +3, r.top+2);
- Line(3, 0);
- Move(2, 0);
- Line(1, 0);
- Move(3, 0);
- Line(4, 0);
- Move(2, 0);
- Line(2, 0);
- }
-
- theGD = (GDHandle) myGDList->GetNextListElem(theGD);
- }
-
- SetClip(saveClip);
- DisposeRgn(saveClip);
- delete myGDList;
- }
-
- pascal void GDeviceWindowDrawingProc ( SInt16 depth,
- SInt16 deviceFlags,
- GDHandle targetDevice,
- SInt32 userData)
- {
- #pragma unused(deviceFlags)
- Rect rampRect, monitorsRect;
- RGBColor myGray = {0xEEEE,0xEEEE,0xEEEE};
- SInt16 windowWidth;
-
- if (depth > 4) //Fill the window with gray to get that look that's all the rage these days
- {
- RGBForeColor(&myGray);
- PaintRect( &((WindowPtr) userData)->portRect);
- }
-
- ForeColor(blackColor);
-
- //Now make the rampRect
- rampRect = ((WindowPtr) userData)->portRect;
- rampRect.bottom -= 5; //A little bit from the bottom
- rampRect.top = rampRect.bottom - 48; //Ramp height needs to be divisible by 8
-
- //Get a little from the edges distance first
- rampRect.left += 16;
- rampRect.right -= 16;
- //Ramp width needs to be be divisible by 32 so the 8-bit palette will
- //draw correctly.
- windowWidth = rampRect.right - rampRect.left;
- rampRect.left += (windowWidth % 32) / 2;
- rampRect.right -= (windowWidth % 32) / 2;
-
- DrawARamp(depth, &rampRect );
- PenSize(2,2);
- FrameRect(&rampRect);
- PenSize(1,1);
-
- //Now make a rect for the mini-monitors display
- monitorsRect = ((WindowPtr) userData)->portRect;
- monitorsRect.top += 50;
- monitorsRect.bottom -= 80;
- //Make the right and left match the ramp for looks
- monitorsRect.left = rampRect.left;
- monitorsRect.right = rampRect.right ;
- //Draw that sucker.
- DrawMiniMonitors(&monitorsRect, targetDevice);
-
-
- }
-
-
- void
- TGDeviceWindow::Drag(Point startPoint)
- {
- //**Bad UI Alert**
- //We are overriding this method because we don't want to allow the
- //user to drag a window of the device it's on.
- GrafPtr savePort;
- RgnHandle draggingRegion;
- long dragResult;
- WindowPeek windowAsWindowPeek = (WindowPeek) fWindow;
- GDHandle thisGD;
- Rect limitRect, slopRect;
- Rect *windowGlobalRect;
- OSErr err;
-
- if (WaitMouseUp()) // de-bounce?
- {
- // Set up the Window Manager port.
-
- GetPort(&savePort);
- SetPort(gWindowManagerPort);
- SetClip(GetGrayRgn());
-
- err = DMGetGDeviceByDisplayID(this->theID, &thisGD, false);
-
- if (err == noErr)
- {
- //Don't want let user drag off this device, so we will set up the slop and limit
- //rectangles to stop them from dragging off the window
- slopRect = (**thisGD).gdRect;
- GlobalToLocal( (Point *) & limitRect.top);
- GlobalToLocal( (Point *) & limitRect.bottom);
- if (MenuBarOnThisScreen(thisGD))
- slopRect.top += LMGetMBarHeight();
-
-
- // if (TestDeviceAttribute (thisGD, mainScreen)) //Account for the menu bar
- // slopRect.top += LMGetMBarHeight();
-
-
- //Set the limit rect to be the bounds of the GDevice adjusted by the offset of the
- //start point in the window.
- limitRect = slopRect;
- windowGlobalRect = &( (**(windowAsWindowPeek)->strucRgn).rgnBBox);
- limitRect.top = limitRect.top + (startPoint.v - windowGlobalRect->top );
- limitRect.left = limitRect.left + (startPoint.h - windowGlobalRect->left );
- limitRect.bottom = limitRect.bottom - (windowGlobalRect->bottom - startPoint.v);
- limitRect.right = limitRect.right - (windowGlobalRect->right - startPoint.h);
-
- draggingRegion = NewRgn();
- CopyRgn(windowAsWindowPeek->strucRgn,draggingRegion);
- dragResult = DragGrayRgn(draggingRegion, startPoint, &limitRect, &slopRect, noConstraint, nil);
- DisposeRgn(draggingRegion);
- }
-
- SetPort(savePort); // Get back to old port
-
- if ((dragResult != 0) && (dragResult != 0x80008000))
- {
- this->Nudge((dragResult & 0xFFFF),(dragResult >> 16));
- }
- }
-
- }
-
- void
- TGDeviceWindow::WindowOnDevice() // •••• PUT THIS IN UTILITIES?
- {
- GDHandle theGD;
- Rect gdRect, intersectionRect, windowRect;
- WindowPeek windowAsWindowPeek = (WindowPeek) this->fWindow;
- SInt16 hMove, vMove;
-
- DMGetGDeviceByDisplayID(this->theID, &theGD, false);
- if (theGD)
- {
- SectRect( &(**theGD).gdRect, &(**windowAsWindowPeek->strucRgn).rgnBBox, &intersectionRect);
- if (! EqualRect(&intersectionRect,&(**windowAsWindowPeek->strucRgn).rgnBBox))
- {
- gdRect = (**theGD).gdRect;
- windowRect = (**windowAsWindowPeek->strucRgn).rgnBBox;
- CenterRectInRect(&gdRect, &windowRect, &hMove, &vMove);
-
- hMove = (**windowAsWindowPeek->contRgn).rgnBBox.left + hMove;
- vMove = (**windowAsWindowPeek->contRgn).rgnBBox.top + vMove;
-
- MoveWindow(this->fWindow, hMove, vMove, false);
-
- }
-
- }
- }
-
- void
- TGDeviceWindow::AdjustMenusBeforeMenuSelection(void)
- {
- Boolean mirrorOn = false;
- Boolean canMirror = false;
-
- DMCanMirrorNow(&canMirror);
-
- if (!canMirror) //can't mirror, so disable the menu and bail
- gMenuBar->EnableAndCheckCommand(cMirroring, false, false);
- else
- {
- DMIsMirroringOn(&mirrorOn);
- if (mirrorOn)
- gMenuBar->EnableAndCheckCommand(cMirroring, true, true);
- else
- gMenuBar->EnableAndCheckCommand(cMirroring, true, false);
- }
- }
-
-